package com.guinea.core.acegi;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

public class DBFilterInvocationDefinitionSource extends
		AbstractFilterInvocationDefinitionSource {

	private boolean convertUrlToLowercaseBeforeComparison = false;

	private boolean useAntPath = false;
	
	private final PathMatcher pathMatcher = new AntPathMatcher();

	private final PatternMatcher matcher = new Perl5Matcher();

	private AcegiCacheManager acegiCacheManager;

	public void setAcegiCacheManager(AcegiCacheManager acegiCacheManager) {
		this.acegiCacheManager = acegiCacheManager;
	}

	/**
	 * 返回当前URL对应的ROLE
	 *
	 * @see org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource#lookupAttributes(java.lang.String)
	 */
	public ConfigAttributeDefinition lookupAttributes(String url) {
		acegiCacheManager.initResourceCache();
//		if (isUseAntPath()) {
//			// Strip anything after a question mark symbol, as per SEC-161.
//			int firstQuestionMarkIndex = url.lastIndexOf("?");
//
//			if (firstQuestionMarkIndex != -1) {
//				url = url.substring(0, firstQuestionMarkIndex);
//			}
//		}
		List urls = acegiCacheManager.getResStrings();

		//倒叙排序
		Collections.sort(urls);
		Collections.reverse(urls);
		if (convertUrlToLowercaseBeforeComparison) {
			url = url.toLowerCase();
		}
		String authoritiesStr = "";
		GrantedAuthority[] authorities = new GrantedAuthority[0];
		for (Iterator iterator = urls.iterator(); iterator.hasNext();) {
			String resString = (String) iterator.next();
			boolean matched = false;
			if (isUseAntPath()) {
				matched = pathMatcher.match(resString, url);
			} else {
				Pattern compiledPattern;
				Perl5Compiler compiler = new Perl5Compiler();
				try {
					compiledPattern = compiler.compile(resString, Perl5Compiler.READ_ONLY_MASK);
				} catch (MalformedPatternException mpe) {
					throw new IllegalArgumentException("Malformed regular expression: " + resString);
				}

				matched = matcher.matches(url, compiledPattern);
			}
			if (matched) {
				ResourceDetails rd = acegiCacheManager.getAuthorityFromCache(resString);
				if(rd != null){
					authorities = rd.getAuthorities();
					authoritiesStr = addAuthorityStr(authoritiesStr,authorities);
				}
			}
		}
//		超级管理员角色为admin
		authoritiesStr = "admin," + authoritiesStr;
		String authStr = "";
		if(authoritiesStr.length()>0)
			authStr = authoritiesStr.substring(0, authoritiesStr
				.length() - 1);
		authStr = authStr.trim();
		if(authStr.length()>0){
			ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
			configAttrEditor.setAsText(authStr.trim());
			return (ConfigAttributeDefinition) configAttrEditor.getValue();
		}
		return null;
	}
	private String addAuthorityStr(String authoritiesStr,GrantedAuthority[] authorities){
		if (authorities.length > 0) {
			for (int i = 0; i < authorities.length; i++) {
				authoritiesStr += authorities[i].getAuthority() + ",";
			}
		}
		return authoritiesStr;
	}
	public Iterator getConfigAttributeDefinitions() {
		return null;
	}

	public void setConvertUrlToLowercaseBeforeComparison(
			boolean convertUrlToLowercaseBeforeComparison) {
		this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
	}

	public boolean isConvertUrlToLowercaseBeforeComparison() {
		return convertUrlToLowercaseBeforeComparison;
	}

	public boolean isUseAntPath() {
		return useAntPath;
	}

	public void setUseAntPath(boolean useAntPath) {
		this.useAntPath = useAntPath;
	}

}
